// 一、数据类型
/*
js基本七种数据类型为：
1、String类型，用于表示字符串；
2、Number类型，用于表示数字；
3、Boolean类型；
4、Symbol类型，代表独一无二的值；
5、Undefined类型；
6、Null类型；
7、Object类型。
*/
// 二、promise原理及应用
/*
Promise
异步操作队列化，按照期望的顺序执行，返回符合预期的结果
是异步编程的一种解决方案：
从语法上讲，promise是一个对象，
从它可以获取异步操作的消息；
从本意上讲，它是承诺，承诺它过一段时间会给你一个结果，
其实是一个构造函数，自己身上有all、reject、resolve，
race这几个方法，原型上有then、catch，finally等方法。
promise有三种状态： pending(等待态)，fulfiled(成功态)，rejected(失败态)；
状态一旦改变，就不会再变
3个缺点：
1、无法取消promise,一旦新建，立即执行，无法中断；
2、promise内部抛出的错误需要设置回调函数才能反映到外部；
3、处于pending状态时，无法得到promise处于哪一个阶段。
*/

// ES6  语法

// vue2 的 响应式原理
// 利用ES5  Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。
/*
响应过程:
首先要对数据(data)进行劫持监听，
所以我们需要设置一个监听器Observer，
用来监听所有属性。如果属性发上变化了，
就需要告诉订阅者Watcher看是否需要更新。
因为订阅者是有很多个，所以我们需要有一个消息订阅器（发布者）
Dep来专门收集这些订阅者，
然后在监听器Observer和订阅者Watcher之间进行统一管理的。
接着，我们还需要有一个指令解析器Compile，对每个节点元素进行扫描和解析，
将相关指令对应初始化成一个订阅者Watcher，并替换模板数据或者绑定相应的函数，
此时当订阅者Watcher接收到相应属性的变化，就会执行对应的更新函数，从而更新视图。
*/


// vue2和vue3的区别
//
//
// 1、vue3完全支持typescript，提高项目的可维护性
// 2、Fragment：模板更简单。
// vue3用到了一个虚拟的父级，
// vue2只能有一个父级节点
// 3、 vue2用 new Vue(); vue3用createApp();
// 多个实例时，vue2中的vue实例共享一个Vue构造函数，无法做到完全隔离
// createApp方法返回一个提供上下文的应用实例，应用实例挂载的整个组件共享同一个上下文
//
// 4、vue2 的双向数据绑定是利用ES5  Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。
//
// vue3 中使用了 es6 的 ProxyAPI 对数据代理。
//
// 5、Vue2与Vue3 最大的区别 —
// Vue2使用选项类型API（Options API）对比Vue3合成型API（Composition API）
// 6、建立数据 data
// Vue2 - 这里把数据放入data属性中
// Vue3setup()方法里。
//
// 7、生命周期
// Vue2--------------vue3
// beforeCreate  -> setup()
// created       -> setup()
// beforeMount   -> onBeforeMount
// mounted       -> onMounted
// beforeUpdate  -> onBeforeUpdate
// updated       -> onUpdated
// beforeDestroy -> onBeforeUnmount
// destroyed     -> onUnmounted
// activated     -> onActivated
// deactivated   -> onDeactivated
//
// vue3还提供了两个调试的钩子  onRenderTracked 状态跟踪,onRenderTriggered 状态触发,、

// 8、父子传参不同
//   vue3是通过setup里的两个参数props 和 第二参数里的emit参数进行接收和向外传递
// 9、vue3多了Teleport组件（瞬移组件） 和Suspense组件 （异步组件)
// 10、v-if和v-for的优先级
// 在vue2中：当v-if和v-for同时使用时，v-for的优先级高于v-if（因此我们通常需要计算属性先对数据进行加工处理，以达到性能优化的目的）
// 在vue3中：当v-if和v-for同时使用时，v-if的优先级高于v-for
// 11、.sync修饰符

// vue2中：由于vue中是单向数据流，父子组件在传值时想要实现v-model的效果就要用到.sync修饰符来实现“双向绑定”
// vue3中：对v-model进行了改造，不再需要 .sync 修饰符即可达到数据双向绑定的效果。在vue3中支持多个 v-model属性，默认使用 modelValue 作为 prop，update:modelValue作为事件，当多个v-model绑定时，书写为例：v-model:title="title"，此时 title 作为prop，update:title 作为事件
// 12、全局挂载问题
// vue2中：绑定全局的变量、方法等：Vue.prototype.$ajax = xxx
// vue3中：const app = createApp({}); app.config.globalProperties.$ajax = xxx
//
// key在template和v-if上的使用
// vue2中：在使用v-if、vi-else、v-else-if时，为了保证dom节点渲染的正确性，通常需要在对应的节点添加不同的key，以确保vue在进行虚拟dom对比时是准确的；vue2中template在v-for循环时是不能设置key的，否则会产生警告（需要给子节点设置key）。
// vue3中：在使用v-if、vi-else、v-else-if时，不用提供唯一的key对dom节点进行区分，因为vue内部会自动生成唯一的key，如果你提供了key，那你就要保证它的唯一性；vue3中template在v-for循环时，key应该设置在template标签上
// 13、vue3 $listeners深层监听被移除
// vue2中：使用$attrs访问传递给组件的属性，使用$listeners访问传递给组件的事件  （需要结合inheritAttrs:false）。
// vue3中：虚拟dom中，事件监听器仅仅是以on为前缀的属性
// 14、this问题
// vue2中：无时无刻都要使用this
// vue3中：因为setup函数的存在，所有的props、data等都不需要用this进行访问（vue3对vue2绝大多数是兼容的，如果你用了vue2相关的东西，那你还是需要像vue2一样书写）


// 1.父传孙数据:provide
//
// 2.子孙得到数据:inject


// 9、箭头函数与普通函数的区别

/*
1、外形不同：箭头函数使用箭头定义，普通函数中没有。
2、 箭头函数全都是匿名函数：普通函数可以有匿名函数，也可以有具名函数
3、箭头函数不能用于构造函数：普通函数可以用于构造函数，以此创建对象实例。
4、普通函数的this指向的是谁调用该函数就指向谁
箭头函数的this指向的是在你书写代码时候的上下文环境对象的this，如果没有上下文环境对象，
那么就指向最外层对象window。
5、箭头函数的arguments指向其父级函数作用域的arguments
6、其他区别：箭头函数不具有 prototype 原型对象。箭头函数不具有 super。
箭头函数不具有 new.target
 */


// 10、computer和watch的区别

/*
Computed：
1.computed： 是计算属性，依赖其它属性值；
2.computed 的值有缓存，只有它依赖的属性值发生改变，下一次获取 computed 的值时才会从新计算 computed 的值；
3.不支持异步，当 Computed 中有异步操作时，无法监听数据的变化
4.如果一个属性是由其他属性计算而来的，这个属性依赖其他的属性，一般会使用computed；
5.如果 computed 属性的属性值是函数，那么默认使用 get 方法，函数的返回值就是属性的属性值；在 computed 中，属性有一个 get 方法和一个 set 方法，当数据发生变化时，会调用 set 方法。

6.computed中的函数直接调用，不用（）。

7.computed中的函数必须用return返回。

8.computed中不能对data中的属性进行赋值操作，
如果对data中的属性进行赋值，data中的属性发生变化，从而触发computed中的函数，就会形成死循环。

Watch：
1.watch：更多的是「观察」的作用，用于监听data中的数据变化，只在被监听的属性值发生变化时执行；
2.watch不支持缓存，当一个属性发生变化时，它就会触发相应的操作；
3.watch支持异步监听
4.watch监听的函数接收两个参数，第一个参数是最新的值，第二个是变化之前的值
5.watch监听数据必须是 data 中声明的或者父组件传递过来的 props 中的数据，当发生变化时，会触发其他操作
6.watch函数有两个的参数：
                 immediate：组件加载立即触发回调函数

deep：深度监听，发现数据内部的变化，在复杂数据类型中使用，例如数组中的对象发生变化。

7.watch中的函数不需要调用；


2、使用场景
Computed：
当我们需要进行数值计算，并且依赖于其它数据时，应该使用 computed，因为可以利用 computed 的缓存特性，避免每次获取值时，都要重新计算；
computed擅长处理的场景：一个数据受多个数据影响，如购物车计算价格

Watch：

当我们需要在数据变化时执行异步或开销较大的操作时，应该使用 watch，使用watch选项允许我们执行异步操作。这些都是计算属性无法做到的。
watch擅长处理的场景：一个数据影响多个数据，如搜索数据

*/

// vue3为什么要用proxy实现双向绑定？
// 1.object.defineProperty的缺点：
// 因为es5的object.defineProperty无法监听对象属性的删除和添加
// 不能监听数组的变化，除了push/pop/shift/unshift/splice/spObject.definert/reverse，其他都不行
// Object.defineProperty只能遍历对象属性直接修改(需要深拷贝进行修改)
// 2.proxy的优点：
// >1、直接监听对象而非属性
// >2、直接监听数组的变化
// >3、拦截的方式有很多种(有13种，set,get,has)
// >4、Proxy返回一个新对象，可以操作新对象达到目的
// 3.proxy的缺点：
// 1、 proxy有兼容性问题，不能用polyfill来兼容（polyfill主要抚平不同浏览器之间对js实现的差异）


// 11、递归求和  递归阶乘
function fn1(n) {
    //跳出条件
    if (n == 1) return 1
    //逻辑  n+（n-1） 的和 //逻辑  n*（n-1） 的和
    return n + fn1(n - 1)
}

console.log(fn1(110))

var data = [
    {
        id: 1,
        name: '家电',
        goods: [
            {
                id: 11,
                gname: '冰箱',
                goods: [
                    {
                        id: 111,
                        gname: '海尔冰箱'
                    },
                    {
                        id: 112,
                        gname: '小天鹅冰箱'
                    },
                ]
            },
            {
                id: 12,
                gname: '洗衣机'
            }
        ]
    },
    {
        id: 2,
        name: '服饰'
    }
]

function getID(json, id) {
    var o = {};
    json.forEach(function (item) {
        if (item.id == id) {
            //console.log(item);
            o = item;
            //2.获取里层数据  可以利用递归函数
            //里面应该有goods这个数组 并且长度不为0
        } else if (item.goods && item.goods.length > 0) {
            o = getID(item.goods, id)
        }
    })
    return o;
}

console.log(getID(data, 12));


/*

十二、常见的浏览器存储主要有：
1.属于文档对象模型：documentcookie，
2.属于浏览器对象模型localStorage，sessionStorage，indexDB

Cookie

h5之前，存储主要用cookies，缺点是在请求头上带着数据，导致流量增加。大小限制4k

localStorage
以键值对(Key-Value)的方式存储，永久存储，永不失效，除非手动删除。IE8+支持，每个域名限制5M

sessionStorage
sessionStorage操作的方法与localStroage是一样的，区别在于sessionStorage在关闭页面后即被清空，而localStorage则会一直保存。很多时候数据只需要在用户浏览一组页面期间使用，关闭窗口后数据就可以丢弃了，这种情况使用sessionStorage就比较方便。

注意，刷新页面sessionStorage不会清除，但是打开同域新页面访问不到

为了弥补cookie的局限性，HTML5中新增了本地存储的解决方案：Web Storage（localStorage和sessionStorage）。

indexedDB是没有存储上限的（一般来说不会小于250M）。它不仅可以存储字符串，还可以存储二进制数据。

区别：
cookie数据始终在同源的http请求中携带（即使不需要），即cookie在浏览器和服务器间来回传递。而sessionStorage和localStorage不会自动把数据发给服务器，仅在本地保存。cookie数据还有路径（path）的概念，可以限制cookie只属于某个路径下。
存储大小限制不同，cookie数据不能超过4k，同时因为每次http请求都会携带cookie，所以cookie只适合保存很小的数据，如会话标识。sessionStorage和localStorage虽然也有存储大小的限制，但比cookie大得多，可以达到5M或更大。
数据有效期不同，sessionStorage：仅在当前浏览器窗口关闭前有效，自然也就不可能持久保持；localStorage：始终有效，窗口或浏览器关闭也一直保存，因此用作持久数据；cookie只在设置的cookie过期时间之前一直有效，即使窗口或浏览器关闭。
作用域不同，sessionStorage不在不同的浏览器页面中共享，即使是同一个页面；localStorage在所有同源窗口中都是共享的；cookie也是在所有同源窗口中都是共享的。
Web Storage 支持事件通知机制，可以将数据更新的通知发送给监听者。
Web Storage 的api接口使用更方便，cookie的原生接口不友好，需要自己封装。
*/
/*
十三、tree-shaking
tree-shaking指的是消除没被引用的模块代码，减少代码体积大小，以提高页面的性能。
Tree-shaking的实现原理
利用ES6模块特性：
只能作为模块顶层的语句出现
import的模块名只能是字符串常量
import binding 是 immutable的，引入的模块不能再进行修改
代码删除：
uglify：判断程序流，判断变量是否被使用和引用，进而删除代码
实现原理可以简单的概况：

ES6 Module引入进行静态分析，故而编译的时候正确判断到底加载了那些模块
静态分析程序流，判断那些模块和变量未被使用或者引用，进而删除对应代码

*/

/*
十四、keep-alive
Vue生命周期(keep-alive缓存特殊activated(组件激活时)
、deactivated(组件停用时))、父子组件的执行顺序
*/


//十五、 为什么Vite启动快

/*
1、底层语言
从底层原理上来说，Vite是基于esbuild预构建依赖。
而esbuild是采用go语言编写，因为go语言的操作是纳秒级别，
而js是以毫秒计数，所以vite比用js编写的打包器快10-100倍。

webpack: 分析依赖=> 编译打包=> 交给本地服务器进行渲染。
首先分析各个模块之间的依赖，然后进行打包，在启动webpack-dev-server，请求服务器时，直接显示打包结果。
webpack打包之后存在的问题：随着模块的增多，会造成打出的 bundle 体积过大，进而会造成热更新速度明显拖慢。
vite: 启动服务器=> 请求模块时按需动态编译显示。
是先启动开发服务器，请求某个模块时再对该模块进行实时编译，
因为现代游览器本身支持ES-Module，所以会自动向依赖的Module发出请求。
所以vite就将开发环境下的模块文件作为浏览器的执行文件，而不是像webpack进行打包后交给本地服务器。

*/
